package com.lonely.deliver.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lonely.common.core.domain.BaseEntity;
import com.lonely.common.core.domain.StatusInfo;
import com.lonely.common.core.page.Condition;
import com.lonely.common.enums.CommonStatus;
import com.lonely.common.enums.DataScope;
import com.lonely.common.threadlocals.DataPermissionThreadLocal;
import com.lonely.common.utils.JsonUtil;
import com.lonely.deliver.domain.dto.QueryOrderDeliverPageDTO;
import com.lonely.deliver.domain.entity.SysOrderDeliver;
import com.lonely.deliver.domain.entity.SysPdaScan;
import com.lonely.deliver.domain.vo.QueryOrderDeliverPageVO;
import com.lonely.deliver.domain.vo.QueryPdaScanSizeInfoVO;
import com.lonely.deliver.enums.OrderDeliverEnum;
import com.lonely.deliver.mapper.SysOrderDeliverMapper;
import com.lonely.deliver.service.IOrderDeliverService;
import com.lonely.deliver.service.IOrderDeliverSynchronizedTaskService;
import com.lonely.deliver.service.IPdaScanService;
import com.lonely.order.domain.dto.api.NumberInfo;
import com.lonely.order.domain.dto.api.QueryDeliverOrderReqDTO;
import com.lonely.order.domain.dto.api.QueryDeliverOrderResDTO;
import com.lonely.order.domain.entity.SysOrder;
import com.lonely.order.domain.entity.SysSheinOpenApiSecret;
import com.lonely.order.service.IMesApiService;
import com.lonely.order.service.ISysSheinOpenApiSecretService;
import com.lonely.order.support.synchronizer.service.SynchronizerOrderDeliverService;
import com.lonely.system.utils.AuthUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author : 黄志标
 * @date: 2025/8/15 17:32
 * @description: 订单发货服务实现类
 */
@Service
@Slf4j
public class OrderDeliverServiceImpl extends ServiceImpl<SysOrderDeliverMapper, SysOrderDeliver> implements IOrderDeliverService {

    @Autowired
    private SynchronizerOrderDeliverService synchronizerOrderDeliverService;

    @Autowired
    private IPdaScanService pdaScanService;

    @Autowired
    private IMesApiService mesApiService;

    @Autowired
    private ISysSheinOpenApiSecretService sheinOpenApiSecretService;

    @Autowired
    private IOrderDeliverSynchronizedTaskService orderDeliverSynchronizedTaskService;

    /**
     * 同步订单发货单数据
     * TODO 该方法不再使用，使用websocket方式进行同步
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @Deprecated
    public void synchronizedOrderDeliver() {
        this.synchronizerOrderDeliverService.synchronizerOrderDeliver();
    }

    /**
     * 订单发货单分页查询
     *
     * @param queryDto
     * @return
     */
    @Override
    public Page<QueryOrderDeliverPageVO> page(QueryOrderDeliverPageDTO queryDto) {
        DataPermissionThreadLocal.setDataPermission(DataScope.ORDER_FACTORY, "o.factory_permission");
        Page<QueryOrderDeliverPageVO> page = Condition.page(queryDto);
        Page<QueryOrderDeliverPageVO> pageResult = super.getBaseMapper().page(page, queryDto);

        if (CollUtil.isNotEmpty(pageResult.getRecords())) {
            List<Long> produceOrderIds = pageResult.getRecords().stream().map(QueryOrderDeliverPageVO::getProduceOrderId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
            List<SysPdaScan> pdaScans = this.pdaScanService.list(new LambdaQueryWrapper<SysPdaScan>()
                    .in(SysPdaScan::getProduceOrderId, produceOrderIds)
                    .eq(SysPdaScan::getStatus, CommonStatus.ENABLE.code)
            );
            Map<String, Integer> pdaScanSizeMap = pdaScans.stream().collect(Collectors.toMap(x -> String.format("%s_%s", x.getProduceOrderId(), x.getSizeName()), SysPdaScan::getSizeQuantity));

            pageResult.setRecords(pageResult.getRecords().stream().peek(orderDeliver -> {
                List<NumberInfo> numberInfos = JsonUtil.parseArray(orderDeliver.getDeliveryInfo(), NumberInfo.class);
                if (CollUtil.isEmpty(numberInfos)) {
                    return;
                }
                List<QueryPdaScanSizeInfoVO> queryPdaScanSizeInfoVOS = numberInfos.stream().map(x -> {
                    QueryPdaScanSizeInfoVO queryPdaScanSizeInfoVO = new QueryPdaScanSizeInfoVO();
                    queryPdaScanSizeInfoVO.setSizeName(x.getSizeName());
                    queryPdaScanSizeInfoVO.setSizeQuantity(MapUtil.getInt(pdaScanSizeMap,
                            String.format("%s_%s", orderDeliver.getProduceOrderId(), x.getSizeName()), 0));
                    return queryPdaScanSizeInfoVO;
                }).collect(Collectors.toList());

                // 设置pda扫码计数总数
                int pdaScanCount = queryPdaScanSizeInfoVOS.stream().mapToInt(QueryPdaScanSizeInfoVO::getSizeQuantity).sum();
                orderDeliver.setPdaScanCount(String.valueOf(pdaScanCount));

                // 设置pda扫码尺码明细
                String pdaScanSizeInfoStr = queryPdaScanSizeInfoVOS.stream().map(x -> String.format("%s:%s", x.getSizeName(), x.getSizeQuantity())).collect(Collectors.joining("/"));
                orderDeliver.setPdaScanSizeInfoStr(pdaScanSizeInfoStr);

            }).collect(Collectors.toList()));
        }

        return pageResult;
    }

    /**
     * 获取状态信息
     *
     * @param queryDto
     * @return
     */
    @Override
    public List<StatusInfo> getStatusInfo(QueryOrderDeliverPageDTO queryDto) {
        // 去除状态过滤
        queryDto.setDeliverStatus(null);
        // 添加数据权限过滤
        String factoryPermissionsJsonStr = AuthUtil.getLoginUserFactoryPermissionsJsonStr();
        List<StatusInfo> statusTotals = super.getBaseMapper().getStatusTotals(queryDto, factoryPermissionsJsonStr);
        return this.extractStatusInfos(statusTotals);
    }

    /**
     * 根据发货单id获取对应详情信息
     *
     * @param id
     * @return
     */
    @Override
    public QueryOrderDeliverPageVO getDetail(Long id) {
        SysOrderDeliver orderDeliver = super.getById(id);
        Assert.notNull(orderDeliver, "发货单不存在");

        QueryOrderDeliverPageVO queryOrderDeliverPageVO = new QueryOrderDeliverPageVO();
        BeanUtils.copyProperties(orderDeliver, queryOrderDeliverPageVO);
        return queryOrderDeliverPageVO;
    }

    /**
     * 查询该发货单的pda 扫描尺码信息
     *
     * @param id
     * @return
     */
    @Override
    public List<QueryPdaScanSizeInfoVO> queryPdaScanSizeInfo(Long id) {
        SysOrderDeliver orderDeliver = super.getById(id);
        Assert.notNull(orderDeliver, "发货单不存在");

        // 查询该发货单中对应的尺码信息
        List<NumberInfo> numberInfos = JsonUtil.parseArray(orderDeliver.getDeliveryInfo(), NumberInfo.class);
        if (CollUtil.isEmpty(numberInfos)) {
            return new ArrayList<>();
        }

        List<String> sizeNames = numberInfos.stream().map(NumberInfo::getSizeName).distinct().collect(Collectors.toList());

        // 获取pda中关于这些尺码的数量信息
        Map<String, Integer> pdaScanSizeNameQuantityMap = this.pdaScanService.list(new LambdaQueryWrapper<SysPdaScan>()
                .eq(SysPdaScan::getProduceOrderId, orderDeliver.getProduceOrderId())
                .in(SysPdaScan::getSizeName, sizeNames)
                .eq(SysPdaScan::getStatus, CommonStatus.ENABLE.code)
        ).stream().collect(Collectors.groupingBy(SysPdaScan::getSizeName, Collectors.summingInt(SysPdaScan::getSizeQuantity)));


        // 组装数据
        List<QueryPdaScanSizeInfoVO> queryPdaScanSizeInfoVOS = new ArrayList<>();
        for (NumberInfo numberInfo : numberInfos) {
            QueryPdaScanSizeInfoVO queryPdaScanSizeInfoVO = new QueryPdaScanSizeInfoVO();
            queryPdaScanSizeInfoVO.setSizeName(numberInfo.getSizeName());
            queryPdaScanSizeInfoVO.setSizeQuantity(MapUtil.getInt(pdaScanSizeNameQuantityMap, numberInfo.getSizeName(), 0));
            queryPdaScanSizeInfoVOS.add(queryPdaScanSizeInfoVO);
        }
        return queryPdaScanSizeInfoVOS;
    }

    /**
     * 同步指定订单集合的发货单数据
     *
     * @param orders
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void synchronizerOrderDeliver(List<SysOrder> orders, boolean addSynchronizedTask) {
        if (CollUtil.isEmpty(orders)) {
            return;
        }

        // 获取工厂密钥信息
        List<Long> factoryIds = orders.stream().map(SysOrder::getFactoryId).distinct().collect(Collectors.toList());
        Map<Long, SysSheinOpenApiSecret> factorySecretMap = sheinOpenApiSecretService.getSheinOpenApiSecretMap(factoryIds);

        if (CollUtil.isEmpty(factorySecretMap)) {
            log.debug("没有查询到工厂密钥信息,同步结束...");
            return;
        }

        // 订单号与订单id的映射
        Map<Long, Long> productOrderMap = orders.stream().collect(Collectors.toMap(SysOrder::getProduceOrderId, BaseEntity::getId, (x, y) -> x));

        //遍历所有工厂的订单
        List<QueryDeliverOrderResDTO> deliverOrderResDTOS = new ArrayList<>();
        List<SysOrder> noSynchronizedOrders = new ArrayList<>();
        for (Map.Entry<Long, SysSheinOpenApiSecret> openApiSecretEntry : factorySecretMap.entrySet()) {
            // 筛选出当前工厂的订单信息
            List<SysOrder> currentFactoryOrders = orders.stream().filter(x -> Objects.equals(x.getFactoryId(), openApiSecretEntry.getKey())).collect(Collectors.toList());
            if (CollUtil.isEmpty(currentFactoryOrders)) {
                continue;
            }

            // 订单分批
            List<List<SysOrder>> currentOrderGroups = CollUtil.split(currentFactoryOrders, 100);
            for (List<SysOrder> currentOrderGroup : currentOrderGroups) {
                QueryDeliverOrderReqDTO reqDTO = new QueryDeliverOrderReqDTO();
                reqDTO.setProduceOrderIdList(currentOrderGroup.stream().map(SysOrder::getProduceOrderId).collect(Collectors.toList()));
                List<QueryDeliverOrderResDTO> currentDeliverOrderResDTOS = this.mesApiService.queryDeliverOrder(openApiSecretEntry.getValue(), reqDTO);
                if (CollUtil.isEmpty(currentDeliverOrderResDTOS)) {
                    noSynchronizedOrders.addAll(currentOrderGroup);
                    continue;
                }

                // 过滤掉子订单号为空的数据
                currentDeliverOrderResDTOS = currentDeliverOrderResDTOS.stream().filter(x -> StrUtil.isNotBlank(x.getSubProduceOrderCode())).collect(Collectors.toList());
                if (CollUtil.isEmpty(currentDeliverOrderResDTOS)) {
                    continue;
                }
                deliverOrderResDTOS.addAll(currentDeliverOrderResDTOS);

                // 等待1秒钟，避免触发限流
                ThreadUtil.sleep(1000);

            }
        }

        // 入库
        if (CollUtil.isNotEmpty(deliverOrderResDTOS)) {
            List<SysOrderDeliver> orderDelivers = deliverOrderResDTOS.stream().map(x -> this.synchronizerOrderDeliverService.buildAddOrderDeliver(x, productOrderMap)).collect(Collectors.toList());
            super.saveBatch(orderDelivers);
        }
        if (addSynchronizedTask && CollUtil.isNotEmpty(noSynchronizedOrders)) {
            // 添加到同步任务表中
            this.orderDeliverSynchronizedTaskService.addOrderDeliverSynchronizedTask(noSynchronizedOrders);
        }

    }


    /**
     * 提取状态信息
     *
     * @param statusTotals
     * @return
     */
    private List<StatusInfo> extractStatusInfos(List<StatusInfo> statusTotals) {
        Map<String, Integer> existsStatusQuantityMap = Optional.ofNullable(statusTotals).orElse(new ArrayList<>()).stream().collect(Collectors.toMap(StatusInfo::getStatus, StatusInfo::getQuantity));

        // 编辑所有状态
        List<StatusInfo> statusInfos = new ArrayList<>();
        for (OrderDeliverEnum.StatusEnum statusEnum : OrderDeliverEnum.StatusEnum.values()) {
            StatusInfo statusInfo = new StatusInfo();
            String status = Convert.toStr(statusEnum.getStatus());
            statusInfo.setStatus(status);
            statusInfo.setStatusName(statusEnum.getStatusStr());
            statusInfo.setQuantity(existsStatusQuantityMap.getOrDefault(status, 0));
            statusInfos.add(statusInfo);
        }
        return statusInfos;
    }

}
